﻿using UnityEngine;
using System.Collections;
using GeneralStorageClasses;
using GUIElements;

namespace TileMapClasses
{
	/// <summary>
	/// Tile manager loader for the overworld.
	/// </summary>
	public delegate void TileManagerLoaded ();

	/// <summary>
	/// Tile manager.
	/// </summary>
	public class tileManager : MonoBehaviour
	{
		//Prefab location
		public GameObject hexTile;

		private bool hidden;

		//Variables for tilemanager
		private Map tileMap;
		private Tile[] tiles;
		private int amountOfTiles;
		private int selectedTileID;
		private static tileManager m_instance;
		private int endTile;
		private int startTile;

		//Event to tell other object that depend on tile manager it has finished loading
		public static event TileManagerLoaded TileManagerFinishedLoading;

		// Use this for initialization
		void Start ()
		{
			m_instance = this;	

			//Make this stay around all the time
			DontDestroyOnLoad (transform.gameObject);

			//Listen for when a tile is selected
			Tile.tileSelected += tileListener;
			Tile.tileControlUpdate += controllListener;

			//Tell Other obejcts it has finished loading
			if (TileManagerFinishedLoading != null) {
				TileManagerFinishedLoading ();
			}

			hidden = false;
		}

		/// <summary>
		/// Inits the tile manager.
		/// </summary>
		/// <param name="width">Width.</param>
		/// <param name="height">Height.</param>
		public void initTileManager (float width, float height)
		{
			//Set the position in the tileMap and get the size to init array of tiles
			tileMap = new Map (transform.position, width, height);
			amountOfTiles = (int)(tileMap.Size);
			tiles = new Tile[amountOfTiles];
		
			//Start position for tiles from object's transform
			float x = tileMap.Position.x;
			float z = tileMap.Position.z;
		
			for (int i = 0; i < tileMap.Height; i++) {
				//Calculate if it is a odd row to be drawn next
				//Reset X to start inline
				x = transform.position.x;
				if (i % 2 == 1) {
					//Offset X if odd
					x += 0.9f;
				}
			
				//Add IDs and prefab to each tile
				for (int j = 0; j < tileMap.Width; j++) {
					int ID = i * (int)tileMap.Width + j;
					GameObject hotPotato = (GameObject)Instantiate (hexTile, new Vector3 (x, transform.position.y, z), Quaternion.identity);
					tiles [ID] = new Tile (hotPotato);
					tiles [ID].TileID = ID;
					x += 1.95f;
				}
				//Increase row
				z += 1.65f;
			}

			//Tell the resourceView to calculate the perturn tiles
			ResourceView.Instance.tileControlListener (0, 0);
		}

		/// <summary>
		/// Hide All tiles.
		/// </summary>
		public void Hide ()
		{
			hidden = true;
			for (int i = 0; i <tiles.Length; i++) {
				tiles [i].Hide ();
			}
		}

		/// <summary>
		/// UnHides all tiles
		/// </summary>
		public void UnHide ()
		{
			hidden = false;
			for (int i = 0; i <tiles.Length; i++) {
				tiles [i].potatas = hexTile;
				tiles [i].Unhide ();
			}
		}

		void OnDestroy ()
		{
			//Remove listener for seleceted tiles
			Tile.tileSelected -= tileListener;
		}

		void Update ()
		{
			if (!hidden) {
				//Update all tiles in the array
				for (int i = 0; i <tiles.Length; i++) {
					tiles [i].Update ();
				}
			}
		}

		/// <summary>
		/// Tiles the listener.
		/// </summary>
		/// <param name="selected">If set to <c>true</c> selected.</param>
		/// <param name="id">Identifier.</param>
		public void tileListener (bool selected, int id)
		{
			//Highlight for the selected tile
			//Use no event when setting to false so it doesn't come back to this function
			if (selected) {
				if (selectedTileID != id) {
					tiles [selectedTileID].SeletedNoEvent = false;
					selectedTileID = id;
				}
			}
		}

		/// <summary>
		/// Controlls the listener.
		/// </summary>
		/// <param name="state">State.</param>
		/// <param name="id">Identifier.</param>
		public void controllListener (int state, int id)
		{
			if (id == endTile) {
				if (state == 1) {
					Debug.Log ("YOU WIN");
				}
			} else if (id == startTile) {
				if (state == 2) {
					Debug.Log ("YOU LOSE");
				}
			}
		}

		/*--------------------------------------------------* 
	 * -------------------ACCESSORS---------------------
	 * -------------------------------------------------*/

		/// <summary>
		/// Gets or sets the <see cref="Tile"/> at the specified index in <see cref="tileManager"/>.
		/// </summary>
		/// <param name="index">Tile index.</param>
		public Tile this [int index] {
			get {
				try {
					return tiles [index];
				} catch (System.IndexOutOfRangeException) {
					Debug.LogError ("TileManager: Index [" + index + "] is out of bounds.");
					return null;
				}
			}
			set {
				tiles [index] = value;
			}
		}

		/// <summary>
		/// Gets or sets the amount of tiles.
		/// </summary>
		/// <value>The amount of tiles.</value>
		public int AmountOfTiles {
			get {
				return amountOfTiles;
			}
			set {
				amountOfTiles = tiles.Length;
			}
		}

		/// <summary>
		/// Gets the selected tile ID.
		/// </summary>
		/// <value>The selected tile I.</value>
		public int SelectedTileID {
			get {
				return selectedTileID;
			}
		}

		/// <summary>
		/// Gets the instance.
		/// </summary>
		/// <value>The instance.</value>
		public static tileManager Instance {
			get {
				if (m_instance == null) {
					Debug.LogError ("TileManager: No instance of this object found! Attactch to gameObject or load in after tileManager is created.");
				}
				return m_instance;
			}
		}

		/// <summary>
		/// Gets the tile map.
		/// </summary>
		/// <value>The tile map.</value>
		public Map TileMap {
			get {
				return tileMap;
			}
		}

		/// <summary>
		/// Gets or sets the start tile.
		/// </summary>
		/// <value>The start tile.</value>
		public int StartTile {
			get {
				return startTile;
			}
			set {
				startTile = value;
			}
		}

		/// <summary>
		/// Gets or sets the end tile.
		/// </summary>
		/// <value>The end tile.</value>
		public int EndTile {
			get {
				return endTile;
			}
			set {
				endTile = value;
			}
		}
	}
}
